<?php
namespace Service;

class MessageCode extends Base
{

    private function sendAliYunMessage($accessKeyId, $accessKeySecret, $PhoneNumbers, $SignName, $TemplateCode, $parameter = [])
    {
        $parameter = [
            'PhoneNumbers' => $PhoneNumbers,/*短信接收号码*/
            'SignName' => $SignName,/*签名名称*/
            'TemplateCode' => $TemplateCode,/*模版CODE*/
            'TemplateParam' => json_encode($parameter, JSON_UNESCAPED_UNICODE),
            'RegionId' => 'cn-hangzhou',
            'Action' => 'SendSms',
            'Version' => '2017-05-25',
            'SignatureMethod' => 'HMAC-SHA1',
            'SignatureNonce' => uniqid(mt_rand(0, 0xffff), true),
            'SignatureVersion' => '1.0',
            'AccessKeyId' => $accessKeyId,
            'Timestamp' => gmdate("Y-m-d\TH:i:s\Z"),
            'Format' => 'JSON'
        ];
        ksort($parameter);
        $sorted = '';
        foreach($parameter as $k => $v){
            $k = $this->sendAliYunMessageCodeEncode($k);
            $v = $this->sendAliYunMessageCodeEncode($v);
            $sorted .= "&{$k}={$v}";
        }
        $sign = base64_encode(hash_hmac('sha1', "GET&%2F&" . $this->sendAliYunMessageCodeEncode(substr($sorted, 1)), $accessKeySecret . '&', true));
        $sign = $this->sendAliYunMessageCodeEncode($sign);
        $url = "http://dysmsapi.aliyuncs.com/?Signature={$sign}{$sorted}";
        $content = file_get_contents($url);
        $content = json_decode($content, true);
        return $content;
    }

    private function sendAliYunMessageCodeEncode($string)
    {
        $result = urlencode($string);
        $result = preg_replace("/\+/", "%20", $result);
        $result = preg_replace("/\*/", "%2A", $result);
        $result = preg_replace("/%7E/", "~", $result);
        return $result;
    }

    public function send($phone, $key, $parameter = [])
    {
        $config = getConfig('code', $key);
        return $this->sendAliYunMessage($config['access_key_id'], $config['access_key_secret'], $phone, $config['sign_name'], $config['template_code'], $parameter);
    }

    public function checkPhoneAndCode($phone, $code)
    {
        /*验证手机号码格式*/
        if(!isPhone($phone)){
            return false;
        }
        /*验证验证码格式*/
        if(!isMessageCode($code)){
            return false;
        }
        $cacheMessageCode = $this->get(CACHE_MESSAGECODE);
        $config = getConfig('code', 'default');
        /*验证尝试次数*/
        $tryTotal = $cacheMessageCode->getTryTotal($phone);
        if($tryTotal >= $config['try_total']){
            $cacheMessageCode->addTryTotal($phone);
            return false;
        }
        /*比对验证码*/
        $codeSave = $cacheMessageCode->getCode($phone);
        if(!$codeSave){
            $cacheMessageCode->addTryTotal($phone);
            return false;
        }
        if($codeSave != $code){
            $cacheMessageCode->addTryTotal($phone);
            return false;
        }
        return true;
    }

    public function notApiLimit($ip, $phone)
    {
        $cacheMessageCode = $this->get(CACHE_MESSAGECODE);
        $config = getConfig('code', 'default');
        /*验证ip*/
        $ipLastTime = $cacheMessageCode->getIpLastTime($ip);
        if(getTimestamp() - $ipLastTime <= $config['ip_span_time']){
            return false;
        }
        $ipHourTotal = $cacheMessageCode->getIpHourTotal($ip);
        if($ipHourTotal >= $config['ip_hour_total']){
            return false;
        }
        /*验证phone*/
        $phoneLastTime = $cacheMessageCode->getPhoneLastTime($phone);
        if(getTimestamp() - $phoneLastTime <= $config['phone_span_time']){
            return false;
        }
        $phoneHourTotal = $cacheMessageCode->getPhoneHourTotal($phone);
        if($phoneHourTotal >= $config['phone_hour_total']){
            return false;
        }
        /*验证total*/
        if($cacheMessageCode->getHourTotal() >= $config['hour_total']){
            return false;
        }
        if($cacheMessageCode->getDayTotal() >= $config['day_total']){
            return false;
        }
        return true;
    }

    public function getCode($phone)
    {
        $cacheMessageCode = $this->get(CACHE_MESSAGECODE);
        $code = $cacheMessageCode->getCode($phone);
        if(!$code){
            $code = makeMessageCode();
        }
        return $code;
    }

    public function save($ip, $phone, $code)
    {
        $cacheMessageCode = $this->get(CACHE_MESSAGECODE);
        $cacheMessageCode->send($ip, $phone, $code);
    }

}